<?php
namespace Service\Library;

/**
 * Transform numberId
 */
class LibAlphaId
{
    /**
     * index
     * @var string
     */
    private $index = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789zyxwvutsrqponmlkjihgfedcba';

    /**
     * power
     * @var integer
     */
    private $pow;

    /**
     * solt
     * @var string
     */
    private $solt;

    public function __construct($solt = NULL, $pow = NULL, $index = NULL)
    {
        $this->solt = $solt;
        $this->pow = $pow;
        $index && $this->index = $index;

        $this->_pretreatment();
    }

    /**
     * numberId to hashId
     * @param integer $id
     * @return string
     */
    public function encode($id)
    {
        $string = NULL;

        $index_len = strlen($this->index);

        if(is_numeric($this->pow))
        {
            $this->pow > 0 && $id += pow($index_len, $this->pow);
        }

        for($i = floor(log($id, $index_len)); $i >= 0; $i--)
        {
            $bcp = bcpow($index_len, $i);
            $ibi = floor($id / $bcp) % $index_len;
            $string .= substr($this->index, $ibi, 1);
            $id = $id - ($ibi * $bcp);
        }

        $string = strrev($string);

        return $string;
    }

    /**
     * hashId to numberId
     * @param string $string
     * @return integer
     */
    public function decode($string)
    {
        $id = 0;

        $index_len = strlen($this->index);

        $string = strrev($string);
        $len = strlen($string) - 1;

        for($i = 0; $i <= $len; $i++)
        { 
            $bcp = bcpow($index_len, $len - $i);
            $id = $id + strpos($this->index, substr($string, $i, 1)) * $bcp;
        }

        if(is_numeric($this->pow))
        {
            $this->pow && $id -= pow($index_len, $this->pow);
        }

        $id = sprintf('%F', $id);
        $id = substr($id, 0, strpos($id, '.'));

        return $id;
    }

    /**
     * pretreatment
     */
    private function _pretreatment()
    {
        if($this->solt)
        {
            // index array
            $n = str_split($this->index);

            // solt array
            $index_len = strlen($this->index);
            $solt_hash = hash('sha256', $this->solt);
            (strlen($solt_hash) < $index_len) && $solt_hash = hash('sha512', $this->solt);
            $solt_hash = substr($solt_hash, 0, $index_len);
            $m = str_split($solt_hash);

            // sort index by solt
            array_multisort($m, SORT_DESC, $n);
            $this->index = implode($n);
        }

        $this->pow && $this->pow--;
    }
}